#!/usr/bin/perl

#defino los campos del archivo maestro de obras
@campos_obra = ("id", "nombre", "correo_prod_general", "correo_prod_ejecutiva");

#defino los campos del archivo maestro de salas
@campos_sala = ("id", "nombre", "capacidad", "direccion", "telefono", "correo");

#defino los campos del archivo de combos (funciones)
@campos_combo = ("id", "id_obra", "fecha", "hora", "id_sala", "butacas_habilitadas", "butacas_disponibles", "req_especiales");

#inicializo un hash para las obras
%obras;

#inicializo un hash para las salas
%salas;

#inicializo un hash para los combos (funciones)
%combos;

#se verifica que el script no este ejecutandose
verificar_ejecucion();

#configuracion inicial
conf_inicial();

#carga inicial
carga_inicial();

#ejecuto la subrutina principal (procesamiento de los parametros)
principal();

#finalmente elimino la marca de ejecucion
eliminar_marca_ejecucion();

#subrutina que verifica que el script no este ejecutandose ya
sub verificar_ejecucion {

	#si existe un archivo de nombre Impirimir_B.pid en el home entonces existe un script ejecutandose
	if(open(ARCH_AUX, $ENV{HOME} . "/Imprimir_B.pid")){

		#cierro el archivo
		close(ARCH_AUX);

		#interrumpo la ejecucion
		fin("Error: existe otra instancia del script ejecutandose\n", 0);
	}
	else {

		#creo la marca de ejecucion		
		crear_marca_ejecucion();
	}
}

#subrutina que crea una marca de ejecucion
sub crear_marca_ejecucion {

	#creo un archivo para indicar que se esta ejecutando el script
	system("touch $ENV{HOME}/Imprimir_B.pid");
}

#subrutina que elimina la marca de ejecucion
sub eliminar_marca_ejecucion {

	#elimino el archivo que indica que se esta ejecutando el script
	system("rm $ENV{HOME}/Imprimir_B.pid");
}

#configuracion, variables de ambiente, etc
sub conf_inicial {

	#tomo la configuracion de las variables de ambiente

	#directorio donde deben generarse los reportes
	$repo_dir = $ENV{REPODIR};

	#directorio donde se encuentran los archivos maestros
	$mae_dir = $ENV{MAEDIR};

	#directorio donde se encuentran los archivos generados por scripts ejecutados anteriormente
	$proc_dir = $ENV{PROCDIR};

	#si alguna de las variables de ambiente no pudo ser recuperada la ejecucion es interrumpida
	if(!$repo_dir || !$mae_dir || !$proc_dir){

		#interrumpo la ejecucion con un error
		fin("No se pudieron obtener las variables del ambiente, probablemente el mismo no esta inicializado\n", 1);
	}

	#construyo la ruta al archivo de reservas aceptadas
	$arch_reservas_ok = $proc_dir . "/reservas.ok";

	#construyo la ruta al archivo de reservas rechazadas
	$arch_reservas_nok = $proc_dir . "/reservas.nok";

	#construyo la ruta al archivo maestro de salas
	$arch_salas = $mae_dir . "/salas.mae";

	#construyo la ruta al archivo maestro de obras
	$arch_obras = $mae_dir . "/obras.mae";

	#construyo la ruta al archivo de combos 
	$arch_combos = $proc_dir . "/combos.dis";

	#obtengo el separador de campos de archivos
	$separador = ';';
}

#subrutina que carga las obras, salas y combos (funciones)
sub carga_inicial {
	
	#carga de obras
	carga_arch_mae("obras", \@campos_obra, $arch_obras);

	#carga de salas
	carga_arch_mae("salas", \@campos_sala, $arch_salas);

	#carga de funciones (si bien el archivo de combos no es un archivo maestro, su estructura nos permite cargarlo mediante la subrutina creada para tal fin)
	carga_arch_mae("combos", \@campos_combo, $arch_combos);
}

#subrutina que carga los registro de un archivo maestro en un hash y lo devuelve, recibe el nombre del hash global para cargar y un array con los nombres de los campos del archivo (este ultimo parametro es recibido por referencia)
sub carga_arch_mae {

	#obtengo el nombre del hash global de resgistros a llenar
	my $nombre_hash = $_[0];

	#obtengo los campos del registro enviados por parametro mediante una referencia a un array
	my @nombres_campos = @{$_[1]};

	#obtengo el nombre del archivo maestro
	my $arch_mae = $_[2];

	#intento abrir el archivo de obras, de no ser posible interrumpo la ejecucion
	open(ARCH_MAE, $arch_mae) || fin("Error: no se pudo abrir el archivo $arch_mae\n", 1); 

	#leo el archivo linea por linea (registro por registro)
	while(my $linea = <ARCH_MAE>) {

		#quito el salto de linea final
		chomp($linea);

		#creo un hash para el registro
		my %registro = {};

		#obtengo los campos por separado en un array utilizando el separador
		my @campos = obtener_campos($linea);

		#el primer campo del hash sera la clave de una funcion, compuesta por la clave de sala y la clave de

		#inicializo un indice de campo
		my $indice = 0;

		#por cada campo del registro
		foreach $campo (@campos){

			#agrego el valor al hash utilizando el nombre del campo como clave
			$registro{$nombres_campos[$indice++]} = $campo; 
		}

		#agrego el registro al hash de registro usando el primer campo como clave
		${$nombre_hash}{@campos[0]} = \%registro; 
	}

	#cierro el archivo de obras
	close(ARCH_MAE);
}

#principal
sub principal {

	#obtengo la cantidad de parametros recibidos desde la linea de comando
	$cant_param = $#ARGV + 1;

	#los parametros pueden ser uno o dos, menos o mas resultara en que se muestre la leyenda de ayuda
	if($cant_param < 1 || $cant_param > 2) {	

		#muestro la leyenda de ayuda
		mostrar_ayuda();
	}
	elsif($cant_param == 1) {


		#si se recibio un solo parametro (tiene que ser -i, -d, -r o -t), genero el listado correspondiente, de lo contrario muestro la ayuda
		if(@ARGV[0] eq "-i" || @ARGV[0] eq "-d" || @ARGV[0] eq "-r" || @ARGV[0] eq "-t") {

			#se genera el listado correspondiente y se imprime por pantalla
			generar_listado(@ARGV[0], 0);
		}
		elsif(@ARGV[0] eq "-a") {

			#limpio la pantalla
			limpiar_pantalla();

			#muestro el menu
			mostrar_menu();
		}
		else {

			#muestro la leyenda de ayuda
			mostrar_ayuda();
		}
	}
	elsif($cant_param == 2) {

		#si recibi dos parametros uno tiene que indicar el listado (-i, -d, -r o -t) y el otro el uso de un archivo (-w)
		if( (@ARGV[0] eq "-i" || @ARGV[0] eq "-d" || @ARGV[0] eq "-r" || @ARGV[0] eq "-t") && @ARGV[1] eq "-w" ){

			# se genera el listado correspondiente y se escribe en un archivo
			generar_listado(@ARGV[0], 1);
		}
		elsif( (@ARGV[1] eq "-i" || @ARGV[1] eq "-d" || @ARGV[1] eq "-r" || @ARGV[1] eq "-t") && @ARGV[0] eq "-w" ){

			# se genera el listado correspondiente y se escribe en un archivo
			generar_listado(@ARGV[1], 1);
		}
		else {

			#muestro la leyenda de ayuda
			mostrar_ayuda();
		}
	}
}

# subrutina que muestra la leyenda de ayuda
sub mostrar_ayuda {

	#imprimo la ayuda en pantalla
	print "uso: ./Imprimir_B -i|-d|-r|-t [-w]\n";
	print "uso: ./Imprimir_B -a\n";
}

# subrutina que muestra un menu que permite generar todos los listados
sub mostrar_menu {

	#inicializo la opcion con un valor que garantice la entrada al while
	$opcion = "";

	#inicializo el flag que determina si uso la pantalla en lugar de un archivo como verdadero
	$generarArchivo = 0;

	#mientras la opcion elegida no sea salir, se sigue mostrando el menu y pidiendole al usuario que elija una opcion
	while ($opcion ne "s") {

		if($opcion eq "i"){

			#genero el listado de invitados
			generar_listado_invitados($generarArchivo);	
	
			#elimino la opcion elegida
			$opcion = "";
		}
		elsif($opcion eq "d"){

			#genero el listado de disponibilidades
			generar_listado_disponibilidades($generarArchivo);

			#elimino la opcion elegida
			$opcion = "";
		}
		elsif($opcion eq "r"){

			#genero el ranking de solicitantes
			generar_ranking_solicitantes($generarArchivo);

			#elimino la opcion elegida
			$opcion = "";
		}
		elsif($opcion eq "t"){

			#genero el listado de tickets
			generar_listado_tickets($generarArchivo);
			
			#elimino la opcion elegida
			$opcion = "";
		}
		elsif($opcion eq "a"){

			#si la generacion de archivo estaba activada, la desactivo, si estaba desactivada, la activo
			if($generarArchivo){
				$generarArchivo = 0;
			}
			else {
				$generarArchivo = 1;
			}

			#elimino la opcion elegida
			$opcion = "";
		}
		else{

			#limpio la pantalla
			limpiar_pantalla();

			#imprimo el titulo del menu
			print "Menu(ingrese la letra correspondiente para acceder a cada opcion):\n\n";

			#imprio las opciones del menu
			print "Listado de (i)nvitados\n";
			print "Listado de (d)isponibilidades\n";
			print "(R)anking de solicitantes\n";
			print "Listado de (t)ickets\n";
			print "(S)alir\n\n";
			print "Generar (a)rchivo: " . ($generarArchivo?"ACTIVADO":"DESACTIVADO") . "\n\n";

			#obtengo una opcion de teclado
			$opcion = obtener_opcion();
		}
	}
}

# subrutina que genera el listado correspondiente al parametro recibido
sub generar_listado {

	if($_[0] eq "-i"){
		generar_listado_invitados($_[1]);
	}
	elsif($_[0] eq "-d"){
		generar_listado_disponibilidades($_[1]);
	}
	elsif($_[0] eq "-r"){
		generar_ranking_solicitantes($_[1]);
	}
	elsif($_[0] eq "-t"){
		generar_listado_tickets($_[1]);
	}
}

# subrutina que genera el listado de invitados
sub generar_listado_invitados {

	#obtengo la opcion de generar archivo o no
	my $generarArchivo = $_[0];

	#obtengo los eventos que tengan al menos un registro de reservas.ok con referencia interna 
	#que a su vez tenga un archivo de invitados con al menos una reserva confirmada
	my @funciones = @{obtener_funciones()};

	#inicializo una opcion
	my $opcion = -1;

	#si no se encontro ninguna funcion (combo)
	if(!@funciones) {

		limpiar_pantalla();
	
		#se avisa al usuario
		print "No se encontraron funciones con reservas confirmadas\n";
	}

	#mientras no se elija un evento (aparentemente si $opcion no es un numero la comparacion con numeros da verdadera) y el array tenga elementos
	while(@funciones && ( !es_numerico($opcion) || $opcion < 0 || $opcion > @funciones ) ){
	
		#limpio la pantalla
		limpiar_pantalla();

		#muestro una leyenda antes de mostrar las funciones con invitados
		print "Se encontraron las siguientes funciones con invitados (ingrese 0 para volver):\n";

		#inicializo un indice de evento
		my $indice = 1;

		#muestro los funciones disponibles
		foreach my $funcion (@funciones){
	
			#muestro la funcion
			print "$indice)$obras{$combos{$funcion}{id_obra}}{nombre}, $salas{$combos{$funcion}{id_sala}}{nombre}, $combos{$funcion}{fecha} $combos{$funcion}{hora} hs.\n";

			#incremento el indice
			$indice++;
		}

		#obtengo una opcion de teclado
		$opcion = obtener_opcion();
	}

	#si la opcion elegida no es cero (es decir, se eligio una funcion) se muestra el listado
	if($opcion != 0 && $opcion != -1){
	
		#limpio la pantalla
		limpiar_pantalla();

		#obtengo el id del combo (funcion) seleccionado
		my $id_combo = $funciones[$opcion - 1];

		#obtengo el id de la obra
		my $id_obra = $combos{$id_combo}{id_obra};

		#obtengo el id de la sala
		my $id_sala = $combos{$id_combo}{id_sala};

		#inicializo un buffer para construir el listado
		my $buffer;
		
		#genero la primer linea del listado
		$buffer = $buffer . "Evento: $funcion Obra: $id_obra-$obras{$id_obra}{nombre} Fecha y Hora: $combos{$id_combo}{fecha}-$combos{$id_combo}{hora} Hs. Sala: $id_sala-$salas{$id_sala}{nombre}\n";

		#obtengo todas las referencias de solicitantes para la funcion seleccionada
		my @solicitantes = @{obtener_solicitantes($id_combo)};

		#por cada referencia
		foreach $sol (@solicitantes) {

			#muestro la referencia del solicitante	
			$buffer = $buffer .  "REFERENCIA INTERNA DEL SOLICITANTE: $sol\n";

			#intento abrir el archivo de invitados del solicitante
			if(open(INVITADOS, $repo_dir . "/" . $sol . ".inv")) {

				#inicializo un acumulador de reservas
				my $reservas = 0;

				#recorro el archivo de invitados
				while(my $linea_inv = <INVITADOS>) {

					#quito el fin de linea
					chomp($linea_inv);

					#quito cualquier retorno de carro que pueda haber
					$linea_inv =~ s/\r//g;

					#obtengo los campos del registro de invitados
					my @campos_inv = split($separador, $linea_inv);

					#obtengo el nombre del invitado
					my $invitado = @campos_inv[0];

					#inicializo la cantidad de acompaniantes
					my $cant_acom = 0;

					#si el registro trae cantidad de acompaniantes
					if(@campos_inv[2]) {
					
						#actualizo la cantidad de acompaniantes del invitado
						$cant_acom = @campos_inv[2];
					}

					#actualizo la cantidad de reservas (teniendo en cuenta el nuevo invitado y sus acompaniantes, de tenerlos)
					$reservas = $reservas + 1 + $cant_acom;

					#muestro el invitado
					$buffer = $buffer . "$invitado, $cant_acom, $reservas\n";	
				}		

				#cierro el archivo de invitados
				close(INVITADOS);

				#muestro el total de reservas confirmadas del solicitante
				$buffer = $buffer . "Total: $reservas\n";
			}
			else {

				#si no hay archivo de invitados se informa
				$buffer = $buffer . "Sin listado de invitados\n";
			}
		}

		#el reporte se muestra por pantalla
		print $buffer;

		#si es necesario, tambien se guarda en un archivo
		if($generarArchivo) {

			#guardo el reporte completo en un archivo
			guardar($repo_dir . "/" . $id_combo . ".inv", $buffer);
		}
	}

	#espero una tecla antes de continuar
	pausa();
}

# subrutina que devuelve todas las funciones que tengan al menos un registro en reservas.ok con referencia interna que a su vez tengo un archivo de invitados
#con al menos una reserva confirmada
sub obtener_funciones {

	#inicializo un array para los ids de las funciones 
	my @funciones;

	#inicializo un hash auxiliar para no repetir funciones 
	my %aux_func_hash;

	#abro el archivo de reservas aceptadas
	open(RESERVAS_OK, $arch_reservas_ok) || fin("error: no se pudo abrir el archivo $arch_reservas_ok", 1);

	#leo el archivo linea por linea
	while(my $linea_res = <RESERVAS_OK> ) {

		#por cada registro, obtengo los campos 
		my @campos_reserva = split($separador, $linea_res);

		#si el registro posee una referencia interna de solicitante
		if(@campos_reserva[8] ne "") {
		
			#construyo la ruta al archivo de invitados del solicitante
			my $arch_inv_sol = $repo_dir . "/" . @campos_reserva[8] . ".inv";

			#si existe, abro el archivo de invitados
			if(open(INVITADOS, $arch_inv_sol)) {

				#si se pudo abrir el archivo de invitados (y por lo tanto, este existe) se verifica que haya al menos una reserva 
				#(es decir, que el archivo contenga al menos una linea)
				if(my $linea_inv = <INVITADOS>) {

					#guardo en el hash un 1 bajo el id del evento como clave (con esto logro almacenar los id de combo sin repetir)
					$aux_func_hash{@campos_reserva[7]}{1};
				}
	
				#cierro el archivo de invitados
				close(INVITADOS);
			}
		}
	}

	#cierro el archivo de reservas aceptadas
	close(RESERVAS_OK);

	#recorro los id de combo guardados y los guardo en el array
	foreach $id_combo (keys(%aux_func_hash)) {

		#agrego el id del combo (evento) al array
		push(@funciones, $id_combo);
	}

	#ordeno las funciones por id (asumiendo que mayor id indica mayor fecha)
	@funciones = sort {$a cmp $b} @funciones;

	#devuelve una referencia al array de eventos construido	
	return \@funciones;
}

# subrutina que devuelve una referencia a un array con todos las referencias de solicitantes ordenadas de manera alfabetica de manera descendente
sub obtener_solicitantes {

	#obtengo el id de la funcion seleccionada de los parametros
	my $id_combo_sel = $_[0];

	#inicializo un array para las referencias
	my @referencias;

	#incializo un hash auxiliar para acumular las referencias no repetidas
	my %aux_ref_hash;
	
	#intento abrir el archivo de reservas confirmadas
	open(RESERVAS, $arch_reservas_ok) || fin("Error: no se pudo leer el archivo de reservas confirmadas $arch_reservas_ok\n", 1);

	#por cada linea del archivo extraigo la referencia del solicitante
	while(my $linea_res = <RESERVAS>) {

		#quito el fin de linea
		chomp($linea_res);

		#extraigo los campos del registro de reserva
		my @campos_reserva = split($separador, $linea_res);	

		#obtengo la referencia de solicitante
		my $ref_sol = @campos_reserva[8];

		#obtengo el id de combo (funcion)
		my $id_combo = @campos_reserva[7];

		#si la referencia de solicitante no esta vacia y el codigo de funcion coincide con el seleccionado
		if($ref_sol ne "" && $id_combo eq $id_combo_sel) {

			#inserto un valor en el hash con la referencia como clave
			$aux_ref_hash{$ref_sol} = 1;
		}
	}

	#cierro el archivo de reservas confirmadas
	close(RESERVAS);

	#recorro las claves del hash auxiliar de referencias y las vuelco en un array
	foreach $ref (keys(%aux_ref_hash)) {

		#agrego la referencia al array
		push(@referencias, $ref);
	}

	#ordeno el array de referencias
	@referencias = sort {$a cmp $b} @referencias;

	#devuelvo el array de referencias
	return \@referencias;
}

# subrutina que genera listado de disponibilidades
sub generar_listado_disponibilidades {

	#obtengo la opcion de guardar el archivo de los parametros
	my $guardarArchivo = $_[0];

	#inicializo la opcion para entrar al while
	my $opcion = "";

	#inicializo la cota inferior del rango con una letra para entrar al while
	my $com_rango = "a";

	#inicializo la cota superior del rango con una letra para entrar al while
	my $fin_rango = "b";

	#mientras no se ingrese una expresion valida, pido al usuario una opcion 
	while( $opcion ne "s" && ( ($tipo ne "o" && $tipo ne "s") || !es_numerico($com_rango) || !es_numerico($fin_rango) ) ){

		#limpio la pantalla
		limpiar_pantalla();

		#muestro una leyenda explicativa
		print "Seleccione el o las funciones a incluir en el listado de disponibilidad mediante una expresion con uno de los dos siguientes formatos (o ingrese 's' para volver):\n";
		print "Ejemplo: s<id>-<id> (traera todas las funciones para las salas de id en el rango recibido)\n";
		print "Ejemplo: o<id>-<id> (traera todas las funciones para las obras de id en el rango recibido)\n";

		#obtengo una opcion de teclado
		$opcion = obtener_opcion();

		#intento obtener el caracter que indica si se esta refiriendo a obras o a salas
		$tipo = substr($opcion, 0, 1);

		#intento dividirla segun el separador de rango
		my @rangos = split('-', substr($opcion, 1));

		#intento obtener la cota inferior del rango de ids
		$com_rango = @rangos[0];

		#intento obtener la cota superior del rango de ids
		$fin_rango = @rangos[1];	
	}

	#si se eligio una opcion que no fuera volver
	if($opcion ne "c") {

		#inicializo un buffer para armar el reporte
		my $buffer = "";

		#si la cota inferior es superior a la cota superior intercambio los valores
		if($com_rango > $fin_rango) {
	
			#utilizo una variable auxiliar para el intercambio
			my $aux = $com_rango;
	
			#reemplazo el valor de la cota inferior por el anterior valor de la cota superior
			$com_rango = $fin_rango;

			#reemplazo el valor de la cota superior por el anterior valor de la cota inferior (ubicado en la variable auxiliar)
			$fin_rango = $aux;
		}

		#recorro los combos existentes
		foreach my $id_combo ( keys %combos ) {

			#inicializo una variable para el id de sala u obra
			my $id;

			#obtengo el id de sala u obra segun corresponda
			if($tipo eq "s") {
			
				$id = $combos{$id_combo}{id_sala};
			}
			else {
			
				$id = $combos{$id_combo}{id_obra};
			}	

			#verifico que el id este dentro del rango
			if($id >= $com_rango && $id <= $fin_rango){

				#agrego una linea al listado
				$buffer = $buffer . "$id_combo - $combos{$id_combo}{id_obra} - $combos{$id_combo}{fecha} - $combos{$id_combo}{hora} - $combos{$id_combo}{id_sala} - $combos{$id_combo}{butacas_habilitadas} - $combos{$id_combo}{butacas_disponibles}\n";
			}
		}

		#si el buffer no esta vacio entonces se encontraron funciones y se genero el listado
		if($buffer ne "") {

			#muestro el listado por pantalla
			print $buffer;

			#si se eligio guardar en archivo obtengo un nombre de archivo del usuario
			if($guardarArchivo) {
	
				#inicializo una variable para el nombre del archivo
				my $archivo = "";
				
				#obtengo un nombre de archivo de teclado
				while($archivo eq "" || $archivo eq "combos") {
					
					#leyenda
					print "Ingrese el nombre del archivo donde se guardara el listado\n";
			
					#leo de teclado
					$archivo = obtener_opcion();
				}

				#guardo el archivo
				guardar($repo_dir . "/" . $archivo . ".dis", $buffer);
			}
		}
		else {
	
			#si el buffer estaba vacio no se encontraron funciones asi que aviso al usuario
			print "No se encontro ninguna funcion\n";
		}

		#pauso la ejecucion
		pausa();
	}
}

# subrutina que genera el ranking de solicitantes
sub generar_ranking_solicitantes {

	#obtengo la opcion de guardar el archivo de los parametros
	my $guardarArchivo = $_[0];

	#inicializo un buffer para armar el ranking
	my $buffer = "";

	#intento abrir el archivo de reservas confirmadas
	open(RESERVAS, $arch_reservas_ok) || fin("Error: no se pudo leer el archivo de reservas confirmadas ($arch_reservas_ok)\n", 1);

	#inicializo un hash para el conteo de reservas
	%reservas = {};

	#inicializo un hash para las direcciones de mail de los solicitantes
	%mails = {};

	#leo el archivo de reservas (linea por linea)
	while(my $linea_res = <RESERVAS>) {

		#quito el fin de linea
		chomp($linea_res);

		#obtengo los campos
		my @campos_res = split($separador, $linea_res);

		#obtengo la referencia de solicitante
		my $ref_sol = @campos_res[8];
	
		#si el registro trajo una referencia de solicitante
		if($ref_sol) {

			#si es la primer reserva del solicitante encontrada
			if(!exists($reservas{$ref_sol})) {

				#se inicializa el contador en el hash
				$reservas{$ref_sol} = 0;	
			}

			#incremento el contador en el hash en uno
			$reservas{$ref_sol} = $reservas{$ref_sol} + 1;

			#guardo la direccion de mail (si ya estaba, se pisa)
			$mails{$ref_sol} = @campos_res[10];
		}

	}

	#obtengo las referencias internas de solicitante ordenadas por cantidad de reservas efectuadas
	my @ranking = sort {$reservas{$b} cmp $reservas{$a}} (keys(%reservas));

	#muestro las diez primeras
	for($i = 0; $i < 10 && $i < @ranking - 1; $i++) {

		#obtengo la referencia
		my $referencia = @ranking[$i];

		#muestro la posicicion del ranking
		$buffer = $buffer . "$mails{$referencia}, $reservas{$referencia}\n";
	}

	#muestro el ranking por pantalla
	print $buffer;

	#si se eligio guardar, se guardar un archivo con el ranking
	if($guardarArchivo) {

		#inicializo un numero para describir el archivo
		my $descriptor = 0;

		#intento abrir el directorio donde estan los reportes
		opendir(REPO_DIR, $repo_dir) || "Error: no se pudo abrir el directorio de reportes ($repo_dir)\n";

		#recorro los archivos en el mismo
		while($repo_arch = readdir(REPO_DIR)) {

			#si encuentro un archivo que coincida con el formato "ranking.nnn"
			if($repo_arch =~ /^ranking\..*$/) {

				#tomo lo que esta despues del punto
				my $repo_arch_ext = substr($repo_arch, 8, length($repo_arch));

				#si es un numero y es mayor al descriptor actual, lo tomo como descriptor
				if(es_numerico($repo_arch_ext) && $repo_arch_ext > $descriptor) {

					#actualizo el descriptor
					$descriptor = $repo_arch_ext;
				}
			}
		}

		#cierro el directorio
		closedir(REPO_DIR);

		#sumo uno al descriptor para no pisar ningun archivo de reporte
		$descriptor++;

		#guardo el ranking en un archivo cuyo nombre termina con un nuevo descriptor
		guardar($repo_dir . "/" . "ranking." . $descriptor, $buffer);
	}

	#cierro el archivo de reservas confirmadas
	close(RESERVAS);

	pausa();
}

# subrutina que genera el listado de tickets
sub generar_listado_tickets {

	#obtengo la opcion de guardar de los parametros
	my $guardarArchivo = $_[0];

	#inicializo un buffer para armar el listado
	my $buffer = "";

	#inicializo la opcion para entrar al while
	my $id_combo = -1;

	#obtengo un id de combo del usuario
	while(!exists($combos{$id_combo}) && $id_combo ne "s") { 

		#limpio la pantalla
		limpiar_pantalla();

		#muestro la leyenda
		print "Ingrese un id de combo (funcion) existente o 's' para volver\n";

		#obtengo un id de combo
		$id_combo = obtener_opcion();
	}

	#intento abrir el archivo de reservas confirmadas
	open(RESERVAS, $arch_reservas_ok) || fin("Error: no se pudo abrir el archivo de reservas confirmadas ($arch_reservas_ok)\n", 1);

	#recorro las reservas
	while(my $linea_res = <RESERVAS>) {

		#quito el fin de linea
		chomp($linea_res);

		#obtengo los campos del registro
		my @campos_res = split($separador, $linea_res); 

		#si el id de combo (funcion) coincide con el ingresado
		if(@campos_res[7] eq $id_combo) {

			#obtengo la cantidad de butacas confirmadas
			my $butacas_conf = @campos_res[6];

			#agrego la cantidad de registros para vales por dos entradas necesarios
			for(my $i = 1; $i <= $butacas_conf / 2; $i++) {

				#agrego un registro por un vale de dos entradas
				$buffer = $buffer . "VALE POR 2 ENTRADA" . $separador . @campos_res[1] . $separador . @campos_res[2] . $separador . @campos_res[3] . $separador . @campos_res[5] . $separador . @campos_res[8] . $separador . @campos_res[10] . "\n";

			}

			#si la cantidad de butacas confirmadas era impar
			if($butacas_conf % 2 == 1) {

				#agrego un registro por un vale de una entrada
				$buffer = $buffer . "VALE POR 1 ENTRADA" . $separador . @campos_res[1] . $separador . @campos_res[2] . $separador . @campos_res[3] . $separador . @campos_res[5] . $separador . @campos_res[8] . $separador . @campos_res[10] . "\n";

			}
		}
	}	

	#cierro el archivo de reservas
	close(RESERVAS);
	
	#muestro el listdo por pantalla
	print $buffer;

	#si corresponde, guardo el archivo
	if($guardarArchivo) {

		#guardo el archivo en el directorio de reportes
		guardar($repo_dir . "/" . $id_combo . ".tck", $buffer);
	}
	
	pausa();
}

# subrutina para pausar la ejecucion
sub pausa {

	#imprimo la clasica leyenda de pausa
	print "Presione <ENTER> para continuar...\n";
	
	#obtengo una linea de la entrada standard pero solo porque estoy esperando un <ENTER>
	$aux = <STDIN>;
}

# subrutina que limpia la pantalla
sub limpiar_pantalla {
	system("clear");
}

# subrutine que recibe un registro de campos separados mediante el seperador definido globalmente y devuelve un array de campos alfanumericos
sub obtener_campos {
	return split($separador, $_[0]);
}

# subrutina que obtiene una opcion de teclado
sub obtener_opcion {

	#muestra una leyenda que indica que se debe ingresar una opcion desde teclado
	print "Opcion:";

	#obtengo una linea de la entrada standard
	$opcion = <STDIN>;

	#quito el fin de linea (\n)
	chomp($opcion);

	#devuelvo la opcion ingresada
	return $opcion;
}

# subrutina que devuelve verdadero o falso de acuerdo si el valor recibido es un numero o no
sub es_numerico {
	return $_[0] =~ /^[0-9][0-9]*$/ ;
}

# subrutina que guarda el string recibido en un archivo de texto
sub guardar {

	#obtengo la ruta y nombre del archivo donde guardar
	my $archivo = $_[0];

	#obtengo el contenido a guardar (un string)
	my $contenido = $_[1];

	#intento abrir el archivo para escritura
	open(ARCH_TXT, ">$archivo") || fin("Error: no se pudo abrir para escritura el archivo $archivo\n", 1);

	#escribo en el archivo el string completo
	print ARCH_TXT $contenido;

	#cierro el archivo
	close(ARCH_TXT);	
}

# subrutina que se encarga de terminar la ejecucion de manera abrupta (recibe un mensaje para mostrar como parametro)
sub fin {

	#obtengo el mensaje a mostrar al detener la ejecucion del parametro
	my $mensaje_fin = $_[0];

	#obtengo la opcion de eliminar o no la marca de ejecucion
	my $eliminar_marca = $_[1];

	#si corresponde, quito la marca de ejcucion
	if($eliminar_marca) {
	
		eliminar_marca_ejecucion();
	}
	
	#detengo la ejecucion
	die $mensaje_fin;
}
